JavaScript'in AbortController'ını kullanarak fetch istekleri, zamanlayıcılar ve daha fazlası gibi asenkron işlemleri etkili bir şekilde nasıl iptal edeceğinizi öğrenin, böylece daha temiz ve performanslı kodlar yazın.
JavaScript AbortController: Asenkron İşlem İptalinde Uzmanlaşma
Modern web geliştirmede asenkron işlemler her yerde karşımıza çıkar. API'lerden veri çekmek, zamanlayıcılar ayarlamak ve kullanıcı etkileşimlerini yönetmek genellikle bağımsız olarak ve potansiyel olarak uzun bir süre çalışan kodları içerir. Ancak, bu işlemleri tamamlanmadan önce iptal etmeniz gereken senaryolar vardır. İşte bu noktada JavaScript'teki AbortController
arayüzü devreye girer. DOM işlemlerine ve diğer asenkron görevlere iptal isteklerini bildirmek için temiz ve verimli bir yol sağlar.
İptal Etme İhtiyacını Anlamak
Teknik detaylara girmeden önce, asenkron işlemleri iptal etmenin neden önemli olduğunu anlayalım. Şu yaygın senaryoları göz önünde bulundurun:
- Kullanıcı Gezinmesi: Bir kullanıcı, bir API isteğini tetikleyen bir arama sorgusu başlatır. Eğer istek tamamlanmadan önce hızla farklı bir sayfaya geçerse, orijinal istek alakasız hale gelir ve gereksiz ağ trafiğinden ve potansiyel yan etkilerden kaçınmak için iptal edilmelidir.
- Zaman Aşımı Yönetimi: Bir asenkron işlem için bir zaman aşımı ayarlarsınız. Eğer işlem zaman aşımı dolmadan tamamlanırsa, gereksiz kod yürütülmesini önlemek için zaman aşımını iptal etmelisiniz.
- Bileşen Kaldırılması (Unmounting): React veya Vue.js gibi ön yüz kütüphanelerinde, bileşenler genellikle asenkron isteklerde bulunur. Bir bileşen kaldırıldığında (unmount edildiğinde), o bileşenle ilişkili devam eden tüm istekler, bellek sızıntılarını ve kaldırılmış bileşenleri güncellemekten kaynaklanan hataları önlemek için iptal edilmelidir.
- Kaynak Kısıtlamaları: Kaynakları kısıtlı ortamlarda (örneğin mobil cihazlar, gömülü sistemler), gereksiz işlemleri iptal etmek değerli kaynakları serbest bırakabilir ve performansı artırabilir. Örneğin, kullanıcı sayfanın o bölümünü geçerse büyük bir resim indirmesini iptal etmek.
AbortController ve AbortSignal'e Giriş
AbortController
arayüzü, asenkron işlemleri iptal etme sorununu çözmek için tasarlanmıştır. İki temel bileşenden oluşur:
- AbortController: Bu nesne, iptal sinyalini yönetir. Bir iptal isteği sinyali vermek için kullanılan tek bir yöntemi vardır:
abort()
. - AbortSignal: Bu nesne, bir işlemin iptal edilmesi gerektiğini belirten sinyali temsil eder. Bir
AbortController
ile ilişkilidir ve iptal edilebilir olması gereken asenkron işleme geçirilir.
Temel Kullanım: Fetch İsteklerini İptal Etme
Bir fetch
isteğini iptal etmenin basit bir örneğiyle başlayalım:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP hatası! Durum: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Veri:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch iptal edildi');
} else {
console.error('Fetch hatası:', error);
}
});
// Fetch isteğini iptal etmek için:
controller.abort();
Açıklama:
- Bir
AbortController
örneği oluşturuyoruz. - İlişkili
AbortSignal
'ıcontroller
'dan alıyoruz. signal
'ıfetch
seçeneklerine iletiyoruz.- İsteği iptal etmemiz gerekirse,
controller.abort()
'u çağırıyoruz. .catch()
bloğunda, hatanın birAbortError
olup olmadığını kontrol ediyoruz. Eğer öyleyse, isteğin iptal edildiğini anlıyoruz.
AbortError'u Yönetme
controller.abort()
çağrıldığında, fetch
isteği bir AbortError
ile reddedilecektir. Bu hatayı kodunuzda uygun şekilde yönetmek çok önemlidir. Bunu yapmamak, işlenmemiş promise reddine ve beklenmedik davranışlara yol açabilir.
İşte hata yönetimi ile daha sağlam bir örnek:
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP hatası! Durum: ${response.status}`);
}
const data = await response.json();
console.log('Veri:', data);
return data;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch iptal edildi');
return null; // Veya hatanın daha yukarıda işlenmesi için fırlatın
} else {
console.error('Fetch hatası:', error);
throw error; // Hatanın daha yukarıda işlenmesi için yeniden fırlatın
}
}
}
fetchData();
// Fetch isteğini iptal etmek için:
controller.abort();
AbortError'u Yönetmek için En İyi Uygulamalar:
- Hata adını kontrol edin: Doğru hata türünü yönettiğinizden emin olmak için her zaman
error.name === 'AbortError'
olup olmadığını kontrol edin. - Varsayılan bir değer döndürün veya yeniden fırlatın: Uygulamanızın mantığına bağlı olarak, varsayılan bir değer (ör.
null
) döndürmek veya hatayı çağrı yığınında daha yukarıda işlenmesi için yeniden fırlatmak isteyebilirsiniz. - Kaynakları temizleyin: Asenkron işlem herhangi bir kaynak ayırdıysa (örneğin, zamanlayıcılar, olay dinleyicileri), bunları
AbortError
işleyicisinde temizleyin.
AbortSignal ile Zamanlayıcıları İptal Etme
AbortSignal
, setTimeout
veya setInterval
ile oluşturulan zamanlayıcıları iptal etmek için de kullanılabilir. Bu, yerleşik zamanlayıcı fonksiyonları doğrudan AbortSignal
'ı desteklemediği için biraz daha manuel çalışma gerektirir. İptal sinyalini dinleyen ve tetiklendiğinde zamanlayıcıyı temizleyen özel bir fonksiyon oluşturmanız gerekir.
function cancellableTimeout(callback, delay, signal) {
let timeoutId;
const timeoutPromise = new Promise((resolve, reject) => {
timeoutId = setTimeout(() => {
resolve(callback());
}, delay);
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new Error('Zamanlayıcı İptal Edildi'));
});
});
return timeoutPromise;
}
const controller = new AbortController();
const signal = controller.signal;
cancellableTimeout(() => {
console.log('Zamanlayıcı çalıştı');
}, 2000, signal)
.then(() => console.log("Zamanlayıcı başarıyla tamamlandı"))
.catch(err => console.log(err));
// Zamanlayıcıyı iptal etmek için:
controller.abort();
Açıklama:
cancellableTimeout
fonksiyonu argüman olarak bir geri çağrı (callback), bir gecikme ve birAbortSignal
alır.- Bir
setTimeout
ayarlar ve zamanlayıcı ID'sini saklar. AbortSignal
'aabort
olayını dinleyen bir olay dinleyicisi ekler.abort
olayı tetiklendiğinde, olay dinleyicisi zamanlayıcıyı temizler ve promise'i reddeder.
Olay Dinleyicilerini İptal Etme
Zamanlayıcılara benzer şekilde, olay dinleyicilerini iptal etmek için de AbortSignal
kullanabilirsiniz. Bu, özellikle kaldırılmakta olan bir bileşenle ilişkili olay dinleyicilerini kaldırmak istediğinizde kullanışlıdır.
const controller = new AbortController();
const signal = controller.signal;
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Butona tıklandı!');
}, { signal });
// Olay dinleyicisini iptal etmek için:
controller.abort();
Açıklama:
signal
'ıaddEventListener
yöntemine bir seçenek olarak iletiyoruz.controller.abort()
çağrıldığında, olay dinleyicisi otomatik olarak kaldırılacaktır.
React Bileşenlerinde AbortController
React'te, bir bileşen kaldırıldığında asenkron işlemleri iptal etmek için AbortController
kullanabilirsiniz. Bu, bellek sızıntılarını ve kaldırılmış bileşenleri güncellemekten kaynaklanan hataları önlemek için çok önemlidir. İşte useEffect
kancasını kullanan bir örnek:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP hatası! Durum: ${response.status}`);
}
const data = await response.json();
setData(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch iptal edildi');
} else {
console.error('Fetch hatası:', error);
}
}
}
fetchData();
return () => {
controller.abort(); // Bileşen kaldırıldığında fetch isteğini iptal et
};
}, []); // Boş bağımlılık dizisi, bu etkinin yalnızca bileşen yüklendiğinde bir kez çalışmasını sağlar
return (
{data ? (
Veri: {JSON.stringify(data)}
) : (
Yükleniyor...
)}
);
}
export default MyComponent;
Açıklama:
useEffect
kancası içinde birAbortController
oluşturuyoruz.signal
'ıfetch
isteğine iletiyoruz.useEffect
kancasından bir temizleme fonksiyonu döndürüyoruz. Bu fonksiyon, bileşen kaldırıldığında çağrılacaktır.- Temizleme fonksiyonu içinde, fetch isteğini iptal etmek için
controller.abort()
'u çağırıyoruz.
İleri Düzey Kullanım Senaryoları
AbortSignal'ları Zincirleme
Bazen birden fazla AbortSignal
'ı bir araya zincirlemek isteyebilirsiniz. Örneğin, alt bileşenlerindeki işlemleri iptal etmesi gereken bir üst bileşeniniz olabilir. Bunu, yeni bir AbortController
oluşturarak ve sinyalini hem üst hem de alt bileşenlere geçirerek başarabilirsiniz.
Üçüncü Parti Kütüphanelerle AbortController Kullanımı
AbortSignal
'ı doğrudan desteklemeyen bir üçüncü parti kütüphane kullanıyorsanız, kodunuzu kütüphanenin iptal mekanizmasıyla çalışacak şekilde uyarlamanız gerekebilir. Bu, kütüphanenin asenkron fonksiyonlarını AbortSignal
'ı yöneten kendi fonksiyonlarınızla sarmalamayı içerebilir.
AbortController Kullanmanın Faydaları
- Artan Performans: Gereksiz işlemleri iptal etmek, ağ trafiğini, CPU kullanımını ve bellek tüketimini azaltabilir, bu da özellikle kaynakları kısıtlı cihazlarda performans artışına yol açar.
- Daha Temiz Kod:
AbortController
, iptali yönetmek için standartlaştırılmış ve zarif bir yol sunarak kodunuzu daha okunabilir ve sürdürülebilir hale getirir. - Bellek Sızıntılarının Önlenmesi: Kaldırılmış bileşenlerle ilişkili asenkron işlemleri iptal etmek, bellek sızıntılarını ve kaldırılmış bileşenleri güncellemekten kaynaklanan hataları önler.
- Daha İyi Kullanıcı Deneyimi: Alakasız istekleri iptal etmek, eski bilgilerin görüntülenmesini önleyerek ve algılanan gecikmeyi azaltarak kullanıcı deneyimini iyileştirebilir.
Tarayıcı Uyumluluğu
AbortController
, Chrome, Firefox, Safari ve Edge dahil olmak üzere modern tarayıcılarda yaygın olarak desteklenmektedir. En son bilgiler için MDN Web Docs'taki uyumluluk tablosunu kontrol edebilirsiniz.
Polyfill'ler
AbortController
'ı doğal olarak desteklemeyen eski tarayıcılar için bir polyfill kullanabilirsiniz. Polyfill, eski tarayıcılarda daha yeni bir özelliğin işlevselliğini sağlayan bir kod parçasıdır. İnternette birkaç AbortController
polyfill'i mevcuttur.
Sonuç
AbortController
arayüzü, JavaScript'te asenkron işlemleri yönetmek için güçlü bir araçtır. AbortController
kullanarak, iptal işlemlerini zarif bir şekilde yöneten daha temiz, daha performanslı ve daha sağlam kodlar yazabilirsiniz. API'lerden veri çekiyor, zamanlayıcılar ayarlıyor veya olay dinleyicilerini yönetiyor olun, AbortController
web uygulamalarınızın genel kalitesini artırmanıza yardımcı olabilir.